package tpc2;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.SocketException;
import java.util.ArrayList;

import static commsCPN.EncodeDecode.*;
import commsCPN.JavaCPN;

public class Workers {
	private static Integer numOfWorkers = null;
	private static JavaCPN jCPN = new JavaCPN();
	private static STATES state = STATES.INIT;

	public enum STATES {
		INIT, RECEIVE_COMMITT_MSGS, SEND_VOTES, RECEIVE_DECISIONS;
		public STATES getNext() {
			return this.ordinal() < STATES.values().length - 1 ? STATES
					.values()[this.ordinal() + 1] : STATES.INIT;
		}
	};

	public static void main(String[] args) throws IOException,
			InterruptedException {
		System.out.println("Workers running.");
		String[] received = null;
		ArrayList<Integer> yesVotes = new ArrayList<Integer>();

		ArrayList<Integer> waitAcks = null;
		ArrayList<Integer> waitDescions = null;
		while (true) {
			switch (state) {
			case INIT:
				try {
					jCPN.connect("localhost", 9000);
					received = receive();
					if (received[0].equals("numOfWorkers")) {
						numOfWorkers = Integer.parseInt(received[1]);
						state = state.getNext();
						System.out.println("-> state: RECEIVE_COMMIT_MSGS");
					}
				} catch (java.net.ConnectException e) {
					Thread.sleep(100);
				}
				break;
			case RECEIVE_COMMITT_MSGS: //CanCommit:worker

				int i = numOfWorkers;
				while (i>0) {
					received = receive();
					if (received[0].equals("CanCommit")) {
						i--;
					}
				}
				System.out.println("-> state: SEND_VOTES");
				state = state.getNext();
				break;
			case SEND_VOTES:
				i = 0;
				String resp = null;
				String send = null;
				while (i<numOfWorkers) { //Vote:worker,vote
					if (Math.random() > 0.5D) {
						resp = "Yes";
						yesVotes.add(Integer.valueOf(i));
					} else {
						resp = "No";
					}
					System.out.println("Size yesVotes:" + yesVotes.size());
					send = "Vote:"+ i + "," + resp;
					System.out.println("Send:" + send);
					jCPN.send(new ByteArrayInputStream(send.getBytes()));
					i++;
				}
					
				state = state.getNext();
				System.out.println("-> state: RECEIVE_DECISIONS");
				break;
			case RECEIVE_DECISIONS:
				// receive the expected decisions, reset state.
				while (yesVotes.size() > 0) {
					received = receive();
					if (received[0].equals("Decision")) {//Decision:worker,decision
						String[] decision = received[1].split(",");
						Integer workerId = Integer.parseInt(decision[0].replaceAll("[^0-9]", ""));
						if(yesVotes.contains(workerId))
						{ yesVotes.remove(workerId);	}
					  	jCPN.send(new ByteArrayInputStream(("Ack:"+ workerId).getBytes()));
					}
				}
				jCPN.send(new ByteArrayInputStream("Reset:".getBytes()));
				jCPN.disconnect();
				System.out.println("-> state: INIT (Cycle completed)");
				state = state.getNext();
				break;
			}
		}
	}

	private static String[] receive() {
		String received = null;
		try {
			received = decodeString(jCPN.receive());
		} catch (java.net.SocketException e) {
			state = STATES.INIT;
		}
		System.out.println("Received: " + received);
		return received.split(":");
	}
}
